#include "matrix.h"

#include <QDataStream>

QString MatrixBase::toJSON() const
{
    QStringList colJson;
    colJson << QString::fromLatin1("\"type\":%1").arg(type());
    colJson << QString::fromLatin1("\"rows\":%1").arg(rows());
    colJson << QString::fromLatin1("\"cols\":%1").arg(columns());
    colJson << QString::fromLatin1("\"value\":[%1]").arg(toJSONHelper());
    return QString::fromLatin1("{%1}").arg(colJson.join(QString::fromLatin1(",")));
}

void MatrixBase::serialize(QDataStream& out) const
{
    out << quint8(type()) << qint32(rows()) << qint32(columns());
    serializeHelper(out);
}

void MatrixBase::unserialize(QDataStream &in)
{
    quint8 type;
    int rows, cols;
    in >> type >> rows >> cols;
    unserializeHelper(in);
}

IntMatrix::IntMatrix(int rows, int cols): Matrix(rows, cols)
{

}

QString IntMatrix::toJSONHelper() const
{
    return QString();
}

void IntMatrix::serializeHelper(QDataStream& out) const
{

}

void IntMatrix::unserializeHelper(QDataStream& in)
{

}

FloatMatrix::FloatMatrix(int rows, int cols) : Matrix(rows, cols)
{

}

QString FloatMatrix::toJSONHelper() const
{
    return QString();
}

void FloatMatrix::serializeHelper(QDataStream& out) const
{

}

void FloatMatrix::unserializeHelper(QDataStream& in)
{

}

DoubleMatrix::DoubleMatrix(int rows, int cols) : Matrix(rows, cols)
{

}

QString DoubleMatrix::toJSONHelper() const
{
    return QString();
}

void DoubleMatrix::serializeHelper(QDataStream& out) const
{

}

void DoubleMatrix::unserializeHelper(QDataStream& in)
{

}

ComplexFloatMatrix::ComplexFloatMatrix(int rows, int cols) : Matrix(rows, cols)
{

}

QString ComplexFloatMatrix::toJSONHelper() const
{
    return QString();
}

void ComplexFloatMatrix::serializeHelper(QDataStream& out) const
{

}

void ComplexFloatMatrix::unserializeHelper(QDataStream& in)
{

}

ComplexDoubleMatrix::ComplexDoubleMatrix(int rows, int cols) : Matrix(rows, cols)
{

}

QString ComplexDoubleMatrix::toJSONHelper() const
{
    return QString();
}

void ComplexDoubleMatrix::serializeHelper(QDataStream& out) const
{

}

void ComplexDoubleMatrix::unserializeHelper(QDataStream& in)
{

}

///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
template <typename T>
static inline void printMatrix(QDebug d, const T& m)
{
    int rows = m.rows();
    int cols = m.columns();
    for (int c = 0; c < cols; ++c) {
        for (int r = 0; r < rows; ++r) {
            d << m.value(r, c);
        }
        d << "\n";
    }
}

template <>
static inline void printMatrix<ComplexFloatMatrix>(QDebug d, const ComplexFloatMatrix& m)
{
    int rows = m.rows();
    int cols = m.columns();
    QString str;
    for (int c = 0; c < cols; ++c) {
        for (int r = 0; r < rows; ++r) {
            const std::complex<float>& val = m.value(r, c);
            str = QString("%1+i%2").arg(val.real(), val.imag());
            d << str;
        }
        d << "\n";
    }
}

template <>
static inline void printMatrix<ComplexDoubleMatrix>(QDebug d, const ComplexDoubleMatrix& m)
{
    int rows = m.rows();
    int cols = m.columns();
    QString str;
    for (int c = 0; c < cols; ++c) {
        for (int r = 0; r < rows; ++r) {
            const std::complex<double>& val = m.value(r, c);
            str = QString("%1+i%2").arg(val.real(), val.imag());
            d << str;
        }
        d << "\n";
    }
}

QDebug operator<<(QDebug d, const IntMatrix &m)
{
    d << "Printing IntMatrix:\n";
    printMatrix(d, m);
    return d;
}

QDebug operator<<(QDebug d, const FloatMatrix &m)
{
    d << "Printing FloatMatrix:\n";
    printMatrix(d, m);
    return d;
}

QDebug operator<<(QDebug d, const DoubleMatrix &m)
{
    d << "Printing DoubleMatrix:\n";
    printMatrix(d, m);
    return d;
}

QDebug operator<<(QDebug d, const ComplexFloatMatrix &m)
{
    d << "Printing ComplexFloatMatrix:\n";
    printMatrix<ComplexFloatMatrix>(d, m);
    return d;
}

QDebug operator<<(QDebug d, const ComplexDoubleMatrix &m)
{
    d << "Printing ComplexDoubleMatrix:\n";
    printMatrix<ComplexDoubleMatrix>(d, m);
    return d;
}
